package com.openlogic.logic.controller.datasource;

import java.lang.reflect.InvocationTargetException;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.noear.solon.annotation.Body;
import org.noear.solon.annotation.Controller;
import org.noear.solon.annotation.Delete;
import org.noear.solon.annotation.Get;
import org.noear.solon.annotation.Inject;
import org.noear.solon.annotation.Mapping;
import org.noear.solon.annotation.Param;
import org.noear.solon.annotation.Path;
import org.noear.solon.annotation.Post;
import org.noear.solon.annotation.Put;
import org.noear.solon.auth.annotation.AuthPermissions;
import org.noear.solon.core.handle.Result;
import org.noear.solon.core.handle.UploadedFile;
import org.noear.solon.validation.annotation.Validated;

import com.mybatisflex.core.paginate.Page;
import com.openlogic.common.core.enums.BusinessType;
import com.openlogic.common.core.web.controller.BaseController;
import com.openlogic.common.core.web.domain.PageData;
import com.openlogic.common.core.web.validate.V_A_E;
import com.openlogic.common.datasource.annotation.QzLog;
import com.openlogic.common.plugins.db.api.dto.BaseDataSourceParamDto;
import com.openlogic.common.plugins.db.api.utils.DataSourceUtils;
import com.openlogic.common.plugins.db.excel.param.ExcelDataSourceParamDTO;
import com.openlogic.common.plugins.spi.constants.DataSourceConstants;
import com.openlogic.common.plugins.spi.enums.DbType;
import com.openlogic.datasource.api.dto.ExcelDataSourceDto;
import com.openlogic.datasource.api.entity.DataSourceEntity;
import com.openlogic.datasource.api.param.ConnectionParam;
import com.openlogic.datasource.api.query.DataSourceQuery;
import com.openlogic.datasource.api.vo.DataSourceVo;
import com.openlogic.logic.adaptor.DataSourceAdapter;
import com.openlogic.logic.mapstruct.DataSourceMapperStruct;
import com.openlogic.logic.service.datasource.DataSourceService;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;

/**
 * @ClassName: DataSourceController
 * @Description: 决策数据源管理
 * @author weiyongpeng
 * @date 2024年11月6日 下午9:07:36
 */
@Api(value = "决策数据源管理")
@Controller
@Mapping("logic/datasource")
public class DataSourceController extends BaseController {

	@Inject
	private DataSourceService dataSourceService;
	
	@Inject
	private List<DataSourceAdapter> dataSourceAdapters;
	
	@Inject
	private DataSourceMapperStruct dataSourceMapperStruct;

	/**
	 * 描述：查询系统支持的数据源类型
	 * @Title: listAllDataSourceType
	 * @return
	 * @author weiyongpeng
	 * @date 2024年11月6日 下午9:10:33
	 */
	@ApiOperation(value = "查询系统支持的数据源类型")
	@Get
	@Mapping("listAllDataSourceType")
	@AuthPermissions("logic:datasource:type:list")
	@QzLog(title = "查询系统支持的数据源类型", businessType = BusinessType.LIST)
	public Result<Map<String, List<String>>> listAllDataSourceType() {
		return Result.succeed(dataSourceService.getConnectorTypeAll());
	}

	/**
	 * 描述：新增数据源
	 * @Title: createDataSource
	 * @param jsonStr
	 * @return
	 * @author weiyongpeng
	 * @date 2024年11月17日 下午3:08:07
	 */
	@Post
	@Mapping("addDs/{category}")
	@AuthPermissions("logic:datasource:add")
	@QzLog(title = "新增数据源", businessType = BusinessType.INSERT)
	public Result<Object> createDataSource(@Path("category") String category, @Body String jsonStr) {
		BaseDataSourceParamDto dataSourceParam = DataSourceUtils.buildDatasourceParam(jsonStr);
		DataSourceAdapter dataSourceAdapter = dataSourceAdapters.stream().filter(adaptor -> adaptor.support(category)).findFirst().get();
		dataSourceAdapter.createDataSource(dataSourceParam, null);
		return Result.succeed("添加数据源操作成功");
	}
	
	/**
	* 描述：新增Excel数据源
	* @Title: createExcelDataSource
	* @param category
	* @param name
	* @param file
	* @return
	* @author weiyongpeng
	* @date  2024年11月26日 上午9:38:31
	 */
	@Post
	@Mapping("addExcel/{category}")
	@AuthPermissions("logic:datasource:type:add")
	@QzLog(title = "新增Excel数据源", businessType = BusinessType.INSERT)
	public Result<Object> createExcelDataSource(@Path("category") String category,
			@Validated({ V_A_E.class }) ExcelDataSourceDto excelDataSourceDto, UploadedFile file) {
		BaseDataSourceParamDto dataSourceParamDto = new ExcelDataSourceParamDTO(excelDataSourceDto.getName());
		DataSourceAdapter dataSourceAdapter = dataSourceAdapters.stream().filter(adaptor -> adaptor.support(category))
				.findFirst().get();
		dataSourceAdapter.createDataSource(dataSourceParamDto, file);
		return Result.succeed("添加数据源操作成功");
	}

	/**
	 * 描述：修改数据源
	 * @Title: updateDataSource
	 * @param id
	 * @param jsonStr
	 * @return
	 * @author weiyongpeng
	 * @date 2024年11月17日 下午3:10:11
	 */
	@Put
	@Mapping("editDs/{id}/{category}")
	@AuthPermissions("logic:datasource:edit")
	@QzLog(title = "修改数据源", businessType = BusinessType.UPDATE)
	public Result<Object> updateDataSource(@Path(value = "id") String id, @Path(value = "category") String category,
			@Body String jsonStr) {
		BaseDataSourceParamDto dataSourceParam = DataSourceUtils.buildDatasourceParam(jsonStr);
		dataSourceParam.setId(id);
		DataSourceAdapter dataSourceAdapter = dataSourceAdapters.stream().filter(adaptor -> adaptor.support(category))
				.findFirst().get();
		dataSourceAdapter.updateDataSource(id, dataSourceParam, null);
		return Result.succeed("修改数据源操作成功");
	}
	
	/**
	 * 描述：修改数据源
	 * @Title: updateDataSource
	 * @param id
	 * @param jsonStr
	 * @return
	 * @author weiyongpeng
	 * @date 2024年11月17日 下午3:10:11
	 */
	@Put
	@Mapping(value = "editExcel/{id}/{category}")
	@AuthPermissions("logic:datasource:edit")
	@QzLog(title = "修改Excel数据源", businessType = BusinessType.UPDATE)
	public Result<Object> updateExcelDataSource(@Path(value = "id") String id,
			@Path(value = "category") String category,
			@Validated({ V_A_E.class }) ExcelDataSourceDto excelDataSourceDto, UploadedFile file) {
		BaseDataSourceParamDto dataSourceParam = new ExcelDataSourceParamDTO(excelDataSourceDto.getId(), excelDataSourceDto.getName());
		DataSourceAdapter dataSourceAdapter = dataSourceAdapters.stream().filter(adaptor -> adaptor.support(category))
				.findFirst().get();
		dataSourceAdapter.updateDataSource(dataSourceParam.getId(), dataSourceParam, file);
		return Result.succeed((Object)"修改数据源操作成功");
	}
	
	/**
	* 描述：设置数据源状态
	* @Title: updateDataSource
	* @param id
	* @param jsonStr
	* @return
	* @author weiyongpeng
	* @date  2024年11月26日 下午5:31:33
	 */
	@Put
	@Mapping(value = "status/{id}")
	@AuthPermissions("logic:datasource:edit")
	@QzLog(title = "修改数据源", businessType = BusinessType.UPDATE)
	public Result<Object> updateDataSourceStatus(@Path(value = "id") String id, @Param("status") String status) {
		dataSourceService.updateDataSourceStatus(id, status);
		return Result.succeed("修改数据源状态操作成功");
	}
	
	/**
	* 描述：查看数据源详情
	* @Title: getDataSourceById
	* @param id
	* @return
	* @author weiyongpeng
	 * @throws InvocationTargetException 
	 * @throws IllegalAccessException 
	* @date  2024年11月17日 下午3:50:59
	 */
	@QzLog(title = "通过ID查询信息", businessType = BusinessType.LIST)
	@AuthPermissions("logic:datasource:single")
	@Get
	@Mapping("{id}")
	public Result<DataSourceVo> getDataSourceById(@Path("id") String id) {
		DataSourceEntity dataSourceEntity = dataSourceService.getDataSourceById(id);
		return Result.succeed(dataSourceMapperStruct.toVO(dataSourceEntity));
	}

	/**
	 * 描述：分页查询数据源列表
	 * @Title: getDataSourceList
	 * @param dataSourceQuery
	 * @return
	 * @author weiyongpeng
	 * @date 2024年11月9日 下午5:07:27
	 */
	@QzLog(title = "分页查询数据源列表", businessType = BusinessType.LIST)
	@AuthPermissions("logic:datasource:list")
	@Get
	@Mapping("listPage")
	public PageData<DataSourceVo> getDataSourceList(Page<DataSourceEntity> page,DataSourceQuery dataSourceQuery) {
		startPage(page);
		List<DataSourceEntity> list = dataSourceService.getDataSourceList(dataSourceQuery);
		List<DataSourceVo> collect = list.stream().map(dataSourceMapperStruct::toVO)
				.map(dataSource -> {
					String dbType = dataSource.getDbType();
					String host = "";
					Integer port = 3306;
					if (!dbType.equals(DbType.EXCEL.getDb())) {
						ConnectionParam connectionParams = dataSource.getConnectionParams();
						if (connectionParams != null && !connectionParams.getAddress().equals("")) {
							String address = connectionParams.getAddress();
							if (dbType.equals(DbType.MYSQL.getDb())) { //MySQL
								String temp = address.replace(DataSourceConstants.JDBC_MYSQL, "");
								host = temp.split("\\:")[0];
								port = Integer.parseInt(temp.split("\\:")[1]);
							}else if(dbType.equals(DbType.ORACLE.getDb())) {
								String temp = address.replace(DataSourceConstants.JDBC_ORACLE_SERVICE_NAME, "");
								host = temp.split("\\:")[0];
								port = Integer.parseInt(temp.split("\\:")[1]);
							}
						}
					}else {
						host = null;
						port = null;
					}
					dataSource.setHost(host);
					dataSource.setPort(port);
					return dataSource;
				})
				.collect(Collectors.toList());
		return getPageData(collect);
	}
	
	/**
	 * 描述：单个数据源删除
	 * @Title: deleteDataSourceById
	 * @param id
	 * @return
	 * @author weiyongpeng
	 * @date 2024年11月10日 下午4:46:50
	 */
	@QzLog(title = "单个数据源删除", businessType = BusinessType.DELETE)
	@AuthPermissions("logic:datasource:delete")
	@Delete
	@Mapping("{id}")
	public Result<Object> deleteDataSourceById(@Path String id) {
		dataSourceService.deleteDataSourceById(id);
		return Result.succeed("删除单个数据源操作成功");
	}
	
	/**
	 * 描述：批量删除数据源
	 * @Title: deleteDataSourceBatch
	 * @param ids
	 * @return
	 * @author weiyongpeng
	 * @date 2024年11月10日 下午4:46:29
	 */
	@QzLog(title = "批量数据源删除", businessType = BusinessType.DELETE)
	@AuthPermissions("logic:datasource:delete")
	@Delete
	@Mapping("batch/{ids}")
	public Result<Object> deleteDataSourceBatch(@Path List<String> ids) {
		dataSourceService.deleteDataSourceBatch(ids);
		return Result.succeed("批量删除数据源操作成功");
	}

	/**
	* 描述：检验数据源连通性
	* @Title: connectDataSource
	* @param jsonStr
	* @return
	* @author weiyongpeng
	* @date  2024年11月18日 上午9:24:02
	 */
	@QzLog(title = "检验数据源连通性", businessType = BusinessType.OTHER)
	@AuthPermissions("logic:datasource:check")
	@Put
	@Mapping("checkConnection")
	public Result<Object> connectDataSource(@Body String jsonStr) {
		BaseDataSourceParamDto dataSourceParam = DataSourceUtils.buildDatasourceParam(jsonStr);
		DataSourceUtils.checkDatasourceParam(dataSourceParam);
		ConnectionParam connectionParams = DataSourceUtils.buildConnectionParams(dataSourceParam);
		Boolean flag = dataSourceService.checkConnection(dataSourceParam.getType(), connectionParams);
		return flag ? Result.succeed("数据源连通性校验成功") : Result.failure("数据源连通性校验失败");
	}
	
	/**
	 * 描述：同步对象
	 * @Title: syncMetadata
	 * @param id
	 * @return
	 * @author weiyongpeng
	 * @date 2024年11月12日 下午5:18:49
	 */
	@QzLog(title = "根据url的id来指定同步对象", businessType = BusinessType.OTHER)
	@AuthPermissions("logic:datasource:other")
	@Post
	@Mapping("sync/{id}")
	public Result<Object> syncMetadata(@Path String id) {
		dataSourceService.syncMetadata(id);
		return Result.succeed("数据源结构同步操作成功");
	}

	/**
	 * 描述：刷新元数据缓存
	 * @Title: refreshMetadata
	 * @return
	 * @author weiyongpeng
	 * @date 2024年11月12日 下午5:14:17
	 */
	@QzLog(title = "刷新元数据缓存", businessType = BusinessType.OTHER)
	@AuthPermissions("logic:datasource:other")
	@Get
	@Mapping("refresh")
	public Result<Object> refreshMetadata() {
		dataSourceService.refreshMetadata();
		return Result.succeed("刷新元数据缓存操作成功");
	}
}
